home *** CD-ROM | disk | FTP | other *** search
/ TPUG - Toronto PET Users Group / TPUG Users Group CD / TPUG Users Group CD.iso / AMIGA / AMICUS / AMICUS13.ADF / Gravity / gravity.c < prev    next >
C/C++ Source or Header  |  1986-08-05  |  18KB  |  733 lines

  1. /*
  2.  *  Gravity V2.2          June 17, 1986
  3.  *
  4.  *  This program simulates planets in orbit around a star.
  5.  *  See  "Computer Recreations"
  6.  *       SCIENTIFIC AMERICAN, January 1986.
  7.  *
  8.  *  Data file format:
  9.  *
  10.  *  (The (0,0) point is at the center of the screen.)
  11.  *  Input format (all float values) :
  12.  *      Gravitation Constant, Time Step, Display Scale
  13.  *      Mass Star
  14.  *      X Pos P1, Y Pos P1, X Vel P1, Y Vel P1, Mass P1
  15.  *      X Pos P2, Y Pos P2, X Vel P2, Y Vel P2, Mass P2
  16.  *      X Pos P3, Y Pos P3, X Vel P3, Y Vel P3, Mass P3
  17.  *      . . .
  18.  *
  19.  *
  20.  *  Author:
  21.  *    Peter A. Giancola              CompuServ ID: 76337,2542
  22.  *    8005 Mandan Road #101
  23.  *    Greenbelt, Maryland 20770-2156
  24.  *
  25.  *    Copyright (c) 1986 by Peter A. Giancola
  26.  *    Permission is granted for unrestricted non-commercial use.
  27.  *
  28.  *
  29.  */
  30.  
  31. /*
  32.  * Include all the system defs.
  33.  */
  34.  
  35. #include "exec/types.h"
  36. #include "exec/libraries.h"
  37. #include "graphics/gfxbase.h"
  38. #include "graphics/text.h"
  39. #include "intuition/intuition.h"
  40. #include "intuition/intuitionbase.h"
  41. #include "lattice/math.h"
  42. #include "lattice/stdio.h"
  43.  
  44. /*
  45.  * External math functions
  46.  */
  47.  
  48. extern int SPTst();
  49. extern int SPAbs();
  50. extern int SPSqrt();
  51. extern int SPAdd();
  52. extern int SPSub();
  53. extern int SPMul();
  54. extern int SPDiv();
  55. extern int SPPow();
  56. extern int SPFieee();
  57. extern float SPTieee();
  58.  
  59. /*
  60.  * Declare global variables.
  61.  */
  62.  
  63. FILE *DataFile;
  64. UBYTE FileName[32] = "GRAVITY.DAT";
  65. int running = FALSE;
  66. int saverunning = FALSE;
  67. int title = TRUE;
  68. int req = FALSE;
  69.  
  70. int zero;
  71. int one;
  72. int minus_one;
  73. int two;
  74. int one_hundred;
  75. int minus_one_hundred;
  76. int three_twenty;
  77. int posx[7];                  /* current X positions */
  78. int posy[7];                  /* current Y positions */
  79. int velx[7];                  /* current X velocities */
  80. int vely[7];                  /* current Y velocities */
  81. int mass[7];                  /* mass of planets */
  82. int gmprod[7][7];             /* (G * m1 * m2) product matrix */
  83. int prevx[7];                   /* previous X positions */
  84. int prevy[7];                   /* previous Y positions */
  85.  
  86. int tstep;                    /* magnitude of time step for each update */
  87. int gcons;                    /* gravitation constant */
  88. int scale;                    /* scale of display screen */
  89. int numplanets;                 /* number of planets in system */
  90.  
  91. USHORT menu_num_hide_t  = (1 | (0 << 5));
  92. USHORT menu_num_show_t  = (1 | (1 << 5));
  93. USHORT menu_num_go      = (1 | (2 << 5));
  94. USHORT menu_num_stop    = (1 | (3 << 5));
  95.  
  96. /*
  97.  * Define library and Intuition pointers.
  98.  */
  99.  
  100. struct GfxBase *GfxBase;
  101. struct IntuitionBase *IntuitionBase;
  102. struct RastPort *RastPort;
  103. struct RastPort *AuthorRastPort;
  104. struct ViewPort *ViewPort;
  105. struct Window *Window;
  106. struct Window *AuthorWindow;
  107. struct Screen *Screen;
  108. struct IntuiMessage *Message;
  109. char *MathBase;
  110. char *MathTransBase;
  111.  
  112. /*
  113.  * Define screen, window, menu and items.
  114.  */
  115.  
  116. struct TextAttr Font = 
  117.   {"topax.font", 8, 0, 0};
  118. struct NewScreen NewScreen = 
  119.   {0, 0, 640, 200, 4, 0, 1, HIRES, CUSTOMSCREEN, &Font, 
  120.    "  Gravity V2.2  ", 0, 0};
  121. struct NewWindow NewWindow = 
  122.   {0, 0, 640, 200, -1, -1, REQCLEAR|MENUPICK, BACKDROP|BORDERLESS|ACTIVATE,
  123.    0, 0, 0, 0, 0, 0, 0, 0, 0, CUSTOMSCREEN};
  124. struct NewWindow NewAuthorWindow =
  125.   {100, 50, 500, 85, -1, -1, CLOSEWINDOW, WINDOWDRAG|WINDOWCLOSE|ACTIVATE,
  126.    0, 0, " Author ", 0, 0, 0, 0, 0, 0, CUSTOMSCREEN};
  127. struct StringInfo FileNameString =
  128.   {FileName, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0};
  129. struct Gadget FileNameGadget =
  130.   {0, 10, 15, 260, 10, GADGHCOMP, ENDGADGET, STRGADGET|REQGADGET, 
  131.    0, 0, 0, 0, (APTR)&FileNameString, 0, 0};
  132. struct IntuiText FileNameText =
  133.   {0, 0, JAM1, 65, 1, 0, "Enter file name", 0};
  134. struct Requester FileNameRequester = 
  135.   {0, 50, 50, 280, 30, 0, 0, &FileNameGadget, 0, &FileNameText, 0, 
  136.    8, 0, 0, 0, 0};
  137. struct IntuiText AuthorText[6] =
  138.   {
  139.     {3, 0, JAM2, 5, 15, 0, 
  140.      "Peter A. Giancola", &AuthorText[1]},
  141.     {3, 0, JAM2, 5, 25, 0, 
  142.      "8005 Mandan Road #101", &AuthorText[2]},
  143.     {3, 0, JAM2, 5, 35, 0, 
  144.      "Greenbelt, Maryland 20770-2156", &AuthorText[3]},
  145.     {5, 0, JAM2, 270, 15, 0, 
  146.      "CompuServ ID: 76337,2542", &AuthorText[4]},
  147.     {4, 0, JAM2, 5, 60, 0, 
  148.      "Copyright (c) 1986 by Peter A. Giancola", &AuthorText[5]},
  149.     {4, 0, JAM2, 5, 70, 0, 
  150.      "Permission is granted for unrestricted non-commercial use.", 0}
  151.   };
  152. struct IntuiText MenuItemText[3][5] =
  153.   {
  154.     {
  155.       {0, 1, JAM2, 0, 0, 0, "Load    ", 0},
  156.       {0, 1, JAM2, 0, 0, 0, "Save    ", 0},
  157.       {0, 1, JAM2, 0, 0, 0, "Edit    ", 0},
  158.       {0, 1, JAM2, 0, 0, 0, "Quit    ", 0},
  159.       {0, 0, 0, 0, 0, 0, 0, 0}
  160.     },
  161.     {
  162.       {0, 1, JAM2, 0, 0, 0, "Hide Title", 0},
  163.       {0, 1, JAM2, 0, 0, 0, "Show Title", 0},
  164.       {0, 1, JAM2, 0, 0, 0, "Go        ", 0},
  165.       {0, 1, JAM2, 0, 0, 0, "Stop      ", 0},
  166.       {0, 1, JAM2, 0, 0, 0, "Restart   ", 0}
  167.     },
  168.     {
  169.       {0, 1, JAM2, 0, 0, 0, "Author", 0},
  170.       {0, 0, 0, 0, 0, 0, 0, 0},
  171.       {0, 0, 0, 0, 0, 0, 0, 0},
  172.       {0, 0, 0, 0, 0, 0, 0, 0},
  173.       {0, 0, 0, 0, 0, 0, 0, 0}
  174.     }
  175.   };
  176. struct MenuItem MenuItem[3][5] =
  177.   {
  178.     {
  179.       {&MenuItem[0][1], 0, 0, 80, 10, ITEMTEXT|ITEMENABLED|HIGHBOX,
  180.        0, (APTR)&MenuItemText[0][0], 0, 0, 0, 0},
  181.       {&MenuItem[0][2], 0, 10, 80, 10, ITEMTEXT|HIGHBOX,
  182.        0, (APTR)&MenuItemText[0][1], 0, 0, 0, 0},
  183.       {&MenuItem[0][3], 0, 20, 80, 10, ITEMTEXT|HIGHBOX,
  184.        0, (APTR)&MenuItemText[0][2], 0, 0, 0, 0},
  185.       {0, 0, 30, 80, 10, ITEMTEXT|ITEMENABLED|HIGHBOX,
  186.        0, (APTR)&MenuItemText[0][3], 0, 0, 0, 0},
  187.       {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
  188.     },
  189.     {
  190.       {&MenuItem[1][1], 0, 0, 90, 10, ITEMTEXT|ITEMENABLED|HIGHBOX,
  191.        0, (APTR)&MenuItemText[1][0], 0, 0, 0, 0},
  192.       {&MenuItem[1][2], 0, 10, 90, 10, ITEMTEXT|HIGHBOX,
  193.        0, (APTR)&MenuItemText[1][1], 0, 0, 0, 0},
  194.       {&MenuItem[1][3], 0, 20, 90, 10, ITEMTEXT|ITEMENABLED|HIGHBOX,
  195.        0, (APTR)&MenuItemText[1][2], 0, 0, 0, 0},
  196.       {&MenuItem[1][4], 0, 30, 90, 10, ITEMTEXT|HIGHBOX,
  197.        0, (APTR)&MenuItemText[1][3], 0, 0, 0, 0},
  198.       {0, 0, 40, 90, 10, ITEMTEXT|ITEMENABLED|HIGHBOX,
  199.        0, (APTR)&MenuItemText[1][4], 0, 0, 0, 0}
  200.     },
  201.     {
  202.       {0, 0, 0, 60, 10, ITEMTEXT|ITEMENABLED|HIGHBOX,
  203.        0, (APTR)&MenuItemText[2][0], 0, 0, 0, 0},
  204.       {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
  205.       {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
  206.       {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
  207.       {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
  208.     },
  209.   };
  210. struct Menu Menu[3] =
  211.   {
  212.     {&Menu[1], 0, 0, 80, 10, MENUENABLED, "Projects", &MenuItem[0][0]},
  213.     {&Menu[2], 85, 0, 70, 10, MENUENABLED, "Control", &MenuItem[1][0]},
  214.     {0, 160, 0, 60, 10, MENUENABLED, "Author", &MenuItem[2][0]}
  215.   };
  216.  
  217. /*
  218.  *            G r a v i t y
  219.  */
  220.  
  221. main ()
  222. {
  223.  
  224.   /* Initialize library and Intuition pointers */
  225.  
  226.   AuthorWindow = 0;
  227.   Window = 0;
  228.   Screen = 0;
  229.   IntuitionBase = 0;
  230.   GfxBase = 0;
  231.  
  232.   /* Initialize the system */
  233.  
  234.   dolibs();  /* Open the libraries */
  235.   zero = to_ffp(0.0);
  236.   one = to_ffp(1.0);
  237.   minus_one = to_ffp(-1.0);
  238.   two = to_ffp(2.0);
  239.   one_hundred = to_ffp(100.0);
  240.   minus_one_hundred = to_ffp(-100.0);
  241.   three_twenty = to_ffp(320.0);
  242.   doscreen();  /* Set up the screen and window */
  243.   doplanets();  /* Initialize the planets */
  244.  
  245.   /* Begin running the simulation 'till the universe collapses... */
  246.  
  247.   FOREVER
  248.     {
  249.     domsg();  /* Process any system messages */
  250.     if (running) docycle();  /* Update the planets */
  251.     };
  252. }
  253.  
  254.  
  255. /*
  256.  * Open the libraries
  257.  */
  258.  
  259. dolibs ()
  260. {
  261.   GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",0);
  262.   if (GfxBase == 0) quit();
  263.   IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",
  264.                                                       0);
  265.   if (IntuitionBase == 0) quit();
  266.   MathBase = (char *)OpenLibrary("mathffp.library", 0);
  267.   if (MathBase == 0) quit();
  268.   MathTransBase = (char *)OpenLibrary("mathtrans.library", 0);
  269.   if (MathTransBase == 0) quit();
  270. }
  271.  
  272.  
  273.  
  274. /*
  275.  * Set up the screen and window
  276.  */
  277.  
  278. doscreen ()
  279. {
  280.   Screen = (struct Screen *)OpenScreen(&NewScreen);
  281.   if (Screen == 0) quit();
  282.  
  283.   NewWindow.Screen = Screen;
  284.   NewAuthorWindow.Screen = Screen;
  285.   Window = (struct Window *)OpenWindow(&NewWindow);
  286.   if (Window == 0) quit();
  287.  
  288.   ViewPort = &Screen->ViewPort;
  289.   RastPort = Window->RPort;
  290.   SetMenuStrip(Window, &Menu[0]);
  291.  
  292.   if (title != TRUE)
  293.     {
  294.     OffMenu(Window,menu_num_hide_t);
  295.     OnMenu(Window,menu_num_show_t);
  296.     ShowTitle(Screen,FALSE);
  297.     };
  298.  
  299.   SetRGB4(ViewPort,  0, 00, 00, 00);
  300.   SetRGB4(ViewPort,  1, 13, 13, 13);
  301.   SetRGB4(ViewPort,  2, 00, 00, 13);
  302.  
  303.   SetRGB4(ViewPort,  3, 15, 15, 00);
  304.   SetRGB4(ViewPort,  4, 15, 00, 00);
  305.   SetRGB4(ViewPort,  5, 00, 15, 00);
  306.   SetRGB4(ViewPort,  6, 00, 00, 15);
  307.   SetRGB4(ViewPort,  7, 00, 15, 15);
  308.  
  309.   SetRGB4(ViewPort,  8, 09, 09, 09);
  310.   SetRGB4(ViewPort,  9, 06, 00, 00);
  311.  
  312.   SetRGB4(ViewPort, 10, 08, 08, 00);
  313.   SetRGB4(ViewPort, 11, 08, 00, 00);
  314.   SetRGB4(ViewPort, 12, 00, 08, 00);
  315.   SetRGB4(ViewPort, 13, 00, 00, 08);
  316.   SetRGB4(ViewPort, 14, 00, 08, 08);
  317.  
  318.   SetRGB4(ViewPort, 15, 10, 10, 00);
  319. }
  320.  
  321.  
  322.  
  323. /*
  324.  * Clean up and exit
  325.  */
  326.  
  327. quit ()
  328. {
  329.   if (AuthorWindow)
  330.     {
  331.     running = saverunning;
  332.     SetMenuStrip(Window, &Menu[0]);
  333.     CloseWindow(AuthorWindow);
  334.     AuthorWindow = 0;
  335.     AuthorRastPort = 0;
  336.     };
  337. /*
  338.   if (FileNameWindow)
  339.     {
  340.     running = saverunning;
  341.     SetMenuStrip(Window, &Menu[0]);
  342.     CloseWindow(FileNameWindow);
  343.     FileNameWindow = 0;
  344.     };
  345.  */
  346.   if (Window)
  347.     {
  348.     ClearMenuStrip(Window);
  349.     CloseWindow(Window);
  350.     };
  351.   if (Screen) CloseScreen(Screen);
  352.   if (MathTransBase) CloseLibrary(MathTransBase);
  353.   if (MathBase) CloseLibrary(MathBase);
  354.   if (IntuitionBase) CloseLibrary(IntuitionBase);
  355.   if (GfxBase) CloseLibrary(GfxBase);
  356.   exit();
  357. }
  358.  
  359.  
  360.  
  361. /*
  362.  * Kill screen for restart
  363.  */
  364.  
  365. killscreen ()
  366. {
  367.   if (AuthorWindow)
  368.     {
  369.     running = saverunning;
  370.     SetMenuStrip(Window, &Menu[0]);
  371.     CloseWindow(AuthorWindow);
  372.     AuthorWindow = 0;
  373.     AuthorRastPort = 0;
  374.     };
  375.   if (Window)
  376.     {
  377.     SetRast(RastPort,0);
  378.     };
  379. }
  380.  
  381.  
  382.  
  383. /*
  384.  * Process system messages
  385.  */
  386.  
  387. domsg ()
  388. {
  389.   ULONG class;
  390.   USHORT code;
  391.   USHORT menunum;
  392.   USHORT itemnum;
  393.   int mousex;
  394.   int mousey;
  395.  
  396.   /* If the author window is open, look for close window messages
  397.      from it */
  398.  
  399.   if (AuthorWindow != 0)
  400.     {
  401.     Message = (struct IntuiMessage *)GetMsg(AuthorWindow->UserPort);
  402.     if (Message != 0)
  403.       {
  404.       class = Message->Class;
  405.       ReplyMsg(Message);
  406.       if (class == CLOSEWINDOW)
  407.         {
  408.         running = saverunning;
  409.         CloseWindow(AuthorWindow);
  410.         AuthorWindow = 0;
  411.         AuthorRastPort = 0;
  412.         SetMenuStrip(Window, &Menu[0]);
  413.         };
  414.       };
  415.     };
  416.  
  417.   /* Now look for menu selection messages */
  418.  
  419.   Message = (struct IntuiMessage *)GetMsg(Window->UserPort);
  420.   if (Message != 0)
  421.     {
  422.     class = Message->Class;
  423.     code = Message->Code;
  424.     mousex = Window->MouseX;
  425.     mousey = Window->MouseY;
  426.     ReplyMsg(Message);
  427.     if (class == REQCLEAR)
  428.       {
  429.       killscreen();
  430.       doplanets();
  431.       SetMenuStrip(Window, &Menu[0]);
  432.       OffMenu(Window,menu_num_go);
  433.       OnMenu(Window,menu_num_stop);
  434.       running = saverunning;
  435.       };
  436.  
  437.     if (class == MENUPICK && code != MENUNULL)
  438.       {
  439.       menunum = MENUNUM(code);
  440.       itemnum = ITEMNUM(code);
  441.       switch (menunum)
  442.         {
  443.         case 0:
  444.           /* Projects */
  445.           switch (itemnum)
  446.             {
  447.             case 0:
  448.               /* Load */
  449.               ClearMenuStrip(Window);
  450.               saverunning = TRUE;
  451.               running = FALSE;
  452.               Request(FileNameRequester, Window);
  453.               break;
  454.             case 1:
  455.               /* Save */
  456.               break;
  457.             case 2:
  458.               /* Edit */
  459.               break;
  460.             case 3:
  461.               /* Quit */
  462.               quit();
  463.               break;
  464.             };
  465.           break;
  466.         case 1:
  467.           /* Control */
  468.           switch (itemnum)
  469.             {
  470.             case 0:
  471.               /* Hide Title */
  472.               menu_num_hide_t = code;
  473.               OffMenu(Window,code);
  474.               OnMenu(Window,menu_num_show_t);
  475.               ShowTitle(Screen,FALSE);
  476.               title = FALSE;
  477.               break;
  478.             case 1:
  479.               /* Show Title */
  480.               ShowTitle(Screen,TRUE);
  481.               menu_num_show_t = code;
  482.               OffMenu(Window,code);
  483.               OnMenu(Window,menu_num_hide_t);
  484.               title = TRUE;
  485.               break;
  486.             case 2:
  487.               /* Go */
  488.               menu_num_go = code;
  489.               OffMenu(Window,code);
  490.               OnMenu(Window,menu_num_stop);
  491.               running = TRUE;
  492.               break;
  493.             case 3:
  494.               /* Stop */
  495.               menu_num_stop = code;
  496.               OffMenu(Window,code);
  497.               OnMenu(Window,menu_num_go);
  498.               running = FALSE;
  499.               break;
  500.             case 4:
  501.               /* Restart */
  502.               killscreen();
  503.               doplanets();
  504.               break;
  505.             };
  506.           break;
  507.         case 2:
  508.           /* Author */
  509.           ClearMenuStrip(Window);
  510.           saverunning = running;
  511.           running = FALSE;
  512.           AuthorWindow = (struct Window *)OpenWindow(&NewAuthorWindow);
  513.           if (AuthorWindow == 0) quit();
  514.           AuthorRastPort = AuthorWindow->RPort;
  515.           PrintIText(AuthorRastPort,&AuthorText[0],0,0);
  516.           break;
  517.         };
  518.       };
  519.     };
  520. }
  521.  
  522.  
  523.  
  524. /*
  525.  * Update the planets
  526.  */
  527.  
  528. docycle ()
  529. {
  530.   int tmp;
  531.   int tmp2;
  532.   int i;
  533.   int j;
  534.   int dx;
  535.   int dy;
  536.   int dist;
  537.   int force;
  538.   int forx;
  539.   int fory;
  540.   int scrx;
  541.   int scry;
  542.  
  543.   /* Make one pass for each planet in the system */
  544.  
  545.   for (i = 1; i < numplanets; ++i)
  546.     {
  547.  
  548.     /* Accumulate the forces on the current planet due to 
  549.        all the other planets */
  550.  
  551.     forx = zero;
  552.     fory = zero;
  553.     for (j = 0; j < numplanets; ++j)
  554.       {
  555.       if (j != i)
  556.         {
  557.  
  558.         /* Calculate the distance between the two selected planets */
  559.  
  560.         dx = SPSub (posx[i], posx[j]);
  561.         dy = SPSub (posy[i], posy[j]);
  562.         dist = SPSqrt(SPAdd(SPPow(two,dx),SPPow(two,dy)));
  563.         tmp = SPSub (dist, one);
  564.         if (! SPTst (SPSub (tmp, SPAbs(tmp)))) dist = one;
  565.  
  566.         /* Now calculate the force due to gravity using the G cons *
  567.            M1 * M2 product matrix to speed the calculation. */
  568.  
  569.         force = SPDiv(SPMul(dist, dist), gmprod[i][j]);
  570.  
  571.         /* The force is a vector, so split it into components. */
  572.  
  573.         forx = SPAdd(forx,SPDiv(dist,SPMul(force,dx)));
  574.         fory = SPAdd(fory,SPDiv(dist,SPMul(force,dy)));
  575.         };
  576.       };
  577.  
  578.     /* Use the force vector to calculate the planet's new velocity. */
  579.  
  580.     velx[i] = SPAdd(velx[i], SPMul(SPDiv(mass[i], forx), tstep));
  581.     vely[i] = SPAdd(vely[i], SPMul(SPDiv(mass[i], fory), tstep));
  582.     };
  583.  
  584.   /* Now update the positions of all planets using the accumulated
  585.      velocity. The new positions are scaled and limited to the screen
  586.      boundries. */
  587.  
  588.   for (i = 0; i < numplanets; ++i)
  589.     {
  590.  
  591.     /* Update the X position */
  592.  
  593.     posx[i] = SPAdd(posx[i],SPMul(velx[i],tstep));
  594.     tmp = SPSub (one_hundred, posx[i]);
  595.     tmp2 = SPSub (posx[i], minus_one_hundred);
  596.     if ((! SPTst (SPSub (tmp, SPAbs(tmp)))) ||
  597.         (! SPTst (SPSub (tmp2, SPAbs(tmp2)))))
  598.       {
  599.       velx[i] = zero;
  600.       vely[i] = zero;
  601.       };
  602.     scrx = (int) (SPTieee(SPAdd(SPMul(SPMul(two,scale),posx[i]),
  603.         three_twenty)));
  604.     if (scrx < 0) scrx = 0;
  605.     if (scrx > 639) scrx = 639;
  606.  
  607.     /* Update the Y position */
  608.  
  609.     posy[i] = SPAdd(posy[i],SPMul(vely[i],tstep));
  610.     tmp = SPSub (one_hundred, posy[i]);
  611.     tmp2 = SPSub (posy[i], minus_one_hundred);
  612.     if ((! SPTst (SPSub (tmp, SPAbs(tmp)))) ||
  613.         (! SPTst (SPSub (tmp2, SPAbs(tmp2)))))
  614.       {
  615.       velx[i] = zero;
  616.       vely[i] = zero;
  617.       };
  618.     scry = (int) (SPTieee(SPAdd(SPMul(SPMul(scale,minus_one),posy[i]),
  619.         one_hundred)));
  620.     if (scry < 0) scry = 0;
  621.     if (scry > 199) scry = 199;
  622.  
  623.     /* Now use the saved previous screen position to leave a trail. */
  624.  
  625.     SetAPen(RastPort,(i + 10));
  626.     j = WritePixel(RastPort, prevx[i], prevy[i]);
  627.  
  628.     /* Draw the new position and save it as the previous position. */
  629.  
  630.     SetAPen(RastPort,(i + 3));
  631.     j = WritePixel(RastPort, scrx, scry);
  632.     prevx[i] = scrx;
  633.     prevy[i] = scry;
  634.     };
  635. }
  636.  
  637.  
  638.  
  639. /*
  640.  * Read the initial conditions.
  641.  */
  642.  
  643. doplanets ()
  644. {
  645.   int i;
  646.   int j;
  647.   int scrx;
  648.   int scry;
  649.   float gc;
  650.   float x[4];
  651.   float m[7];
  652.  
  653.   OffMenu(Window,menu_num_stop);
  654.   OnMenu(Window,menu_num_go);
  655.   running = FALSE;
  656.   DataFile = fopen(FileName, "r");
  657.   if (DataFile != NULL)
  658.     {
  659.     j = fscanf(DataFile, "%f %f %f", &gc, &x[0], &x[1]);
  660.     gcons = to_ffp(gc);
  661.     tstep = to_ffp(x[0]);
  662.     scale = to_ffp(x[1]);
  663.     i = 0;
  664.  
  665.     /* Read the star's mass first. */
  666.  
  667.     j = fscanf(DataFile, "%f", &m[i]);
  668.     mass[i] = to_ffp(m[i]);
  669.     posx[i] = zero;
  670.     posy[i] = zero;
  671.     velx[i] = zero;
  672.     vely[i] = zero;
  673.  
  674.     /* Now read the planet's parameters. */
  675.  
  676.     while (j != EOF && i < 5)
  677.       {
  678.       i += 1;
  679.       j = fscanf(DataFile, "%f %f %f %f %f", 
  680.                  &x[0], &x[1], &x[2], &x[3], &m[i]);
  681.       posx[i] = to_ffp(x[0]);
  682.       posy[i] = to_ffp(x[1]);
  683.       velx[i] = to_ffp(x[2]);
  684.       vely[i] = to_ffp(x[3]);
  685.       mass[i] = to_ffp(m[i]);
  686.       };
  687.     numplanets = i;
  688.     i = fclose(DataFile);
  689.  
  690.     /* Initialize the G cons * M1 * M2 product matrix. */
  691.  
  692.     for (i = 0; i < numplanets; ++i)
  693.       {
  694.       scrx = (int) (SPTieee(SPAdd(SPMul(SPMul(two,scale),posx[i]),
  695.           three_twenty)));
  696.       if (scrx < 0) scrx = 0;
  697.       if (scrx > 639) scrx = 639;
  698.       scry = (int) (SPTieee(SPAdd(SPMul(SPMul(scale,minus_one),posy[i]),
  699.           one_hundred)));
  700.       if (scry < 0) scry = 0;
  701.       if (scry > 199) scry = 199;
  702.       prevx[i] = scrx;
  703.       prevy[i] = scry;
  704.       for (j = 0; j < numplanets; ++j)
  705.         {
  706.         if (i != j) gmprod[i][j] = to_ffp(gc * m[i] * m[j]);
  707.         else gmprod[i][j] = zero;
  708.         };
  709.       };
  710.     OffMenu(Window, menu_num_go);
  711.     OnMenu(Window, menu_num_stop);
  712.     running = TRUE;
  713.     };
  714. }
  715.  
  716.  
  717.  
  718. /*
  719.  * convert from Lattice float to FFP.
  720.  */
  721.  
  722. int to_ffp (arg)
  723.   double arg;
  724.   {
  725.   union
  726.     {
  727.     int i;
  728.     float r;
  729.     } temp;
  730.   temp.r = arg;
  731.   return (SPFieee(temp.i));
  732.   }
  733.